﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ServiceBus.Contract;

namespace ServiceBus.Service
{
    public class ServiceController
    {
        #region Events
        public static event EventHandler ServiceOpenedEvent;
        public static event EventHandler ServiceFaultEvent;
        #endregion

        #region Static Properties
        private static ServiceHost ServiceProviderHost = null;
        private static ServiceHost MessageSenderHost = null;
        private static List<ServiceStruct> ServiceHosts = new List<ServiceStruct>();
        private static List<ServiceStruct> MessageHosts = new List<ServiceStruct>();
        #endregion

        #region Static Methods
        public static void AddKnowType(Type type)
        {
            KnowTypes.AddKnownType(type);
        }
        public static void OpenFunctionService<T>(int portnumber, string endpointname)
        {
            string key = portnumber.ToString()+endpointname.ToUpper().Trim();
            string adddress = "net.tcp://localhost:" + portnumber + "/"+endpointname+"Function";
            if (ServiceHosts.FirstOrDefault(s=>s.ServiceKey==key)!=null) throw new ArgumentException("endpoint exists");

            System.ServiceModel.Channels.Binding bind = new NetTcpBinding();
            ServiceHost host = new ServiceHost(typeof(ServiceBus.Service.SAOService<T>));
            host.AddServiceEndpoint(typeof(ServiceBus.Contract.ISAOService),bind, adddress);

            host.Opened += new EventHandler(ServiceProviderHost_Opened);
            host.Faulted += new EventHandler(ServiceProviderHost_Faulted);
            host.Open();
            ServiceHosts.Add(new ServiceStruct { ServiceKey = key, Address = adddress, ServiceHost = host });
        }
        public static void CloseFunctionService(int portnumber, string endpointname)
        {
            string key = portnumber.ToString() + endpointname.ToUpper().Trim();
            ServiceStruct service = ServiceHosts.FirstOrDefault(s => s.ServiceKey == key);
            if (service!=null)
            {
                service.ServiceHost.Opened -= new EventHandler(ServiceProviderHost_Opened);
                service.ServiceHost.Faulted -= new EventHandler(ServiceProviderHost_Faulted);
                service.ServiceHost.Close();
                ServiceHosts.Remove(service);
            }
            else 
                throw new ArgumentException("endpoint does not exist");
        }

        public static void OpenMessageService(int portnumber, string endpointname)
        {
            string key = portnumber.ToString() + endpointname.ToUpper().Trim();
            string address = "net.tcp://localhost:" + portnumber + "/" + endpointname+"Message";
            if (MessageHosts.FirstOrDefault(s=>s.ServiceKey==key)!=null) throw new ArgumentException("endpoint exists");

            System.ServiceModel.Channels.Binding bind = new NetTcpBinding();
            ServiceHost host = new ServiceHost(typeof(ServiceBus.Service.MessageSender));
            host.AddServiceEndpoint(typeof(ServiceBus.Contract.IMessageSender),bind, address);

            host.Opened += new EventHandler(MessageSenderHost_Opened);
            host.Faulted += new EventHandler(MessageSenderHost_Faulted);
            host.UnknownMessageReceived +=
                new EventHandler<UnknownMessageReceivedEventArgs>(MessageSenderHost_UnknownMessageReceived);

            host.Open();
            MessageHosts.Add(new ServiceStruct { ServiceKey = key, Address = address, ServiceHost = host });
        }
        public static void CloseMessageService(int portnumber, string endpointname)
        {
            string key = portnumber.ToString() + endpointname.ToUpper().Trim();
            ServiceStruct service = MessageHosts.FirstOrDefault(s => s.ServiceKey == key);
            if (service!=null)
            {
                service.ServiceHost.Opened -= new EventHandler(MessageSenderHost_Opened);
                service.ServiceHost.Faulted -= new EventHandler(MessageSenderHost_Faulted);
                service.ServiceHost.UnknownMessageReceived -=
                    new EventHandler<UnknownMessageReceivedEventArgs>(MessageSenderHost_UnknownMessageReceived);
                service.ServiceHost.Close();
                MessageHosts.Remove(service);
            }
            else
                throw new ArgumentException("endpoint does not exist");
        }
        /// <summary>
        /// open default service with default name
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="portnumber"></param>
        public static void OpenFunctionService<T>()
        {
            System.ServiceModel.Channels.Binding bind = new NetTcpBinding();

            ServiceProviderHost = new ServiceHost(typeof(ServiceBus.Service.SAOService<T>));
            ServiceProviderHost.AddServiceEndpoint(typeof(ServiceBus.Contract.ISAOService),
                bind, "net.tcp://localhost:8887/FunctionService");
            
            ServiceProviderHost.Opened += new EventHandler(ServiceProviderHost_Opened);
            ServiceProviderHost.Faulted += new EventHandler(ServiceProviderHost_Faulted);
            ServiceProviderHost.Open();
        }
        public static void OpenMessageService()
        {
            System.ServiceModel.Channels.Binding bind = new NetTcpBinding();

            MessageSenderHost = new ServiceHost(typeof(ServiceBus.Service.MessageSender));
            MessageSenderHost.AddServiceEndpoint(typeof(ServiceBus.Contract.IMessageSender),
                bind, "net.tcp://localhost:8887/MessageService");
            MessageSenderHost.Opened += new EventHandler(MessageSenderHost_Opened);
            MessageSenderHost.Faulted += new EventHandler(MessageSenderHost_Faulted);
            MessageSenderHost.UnknownMessageReceived +=
                new EventHandler<UnknownMessageReceivedEventArgs>(MessageSenderHost_UnknownMessageReceived);
            MessageSenderHost.Open();
        }


        public static void CloseFunctionService()
        {
            ServiceProviderHost.Close();
        }
        public static void CloseMessageService()
        {
            MessageSenderHost.Close();
        }
        public static ServiceStruct[] GetAvaliableServices()
        {
            return ServiceHosts.ToArray();
        }
        public static ServiceStruct[] GetAvaliableMessage()
        {
            return MessageHosts.ToArray();
        }

        static void MessageSenderHost_UnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
        {
        }

        static void MessageSenderHost_Faulted(object sender, EventArgs e)
        {
            if (ServiceFaultEvent != null) ServiceFaultEvent("Message Service", e);
        }

        static void MessageSenderHost_Opened(object sender, EventArgs e)
        {
            if (ServiceOpenedEvent != null) ServiceOpenedEvent("Message Service", e);
        }

        static void ServiceProviderHost_Faulted(object sender, EventArgs e)
        {
            if (ServiceFaultEvent != null) ServiceFaultEvent("Function Service", e);
        }

        static void ServiceProviderHost_Opened(object sender, EventArgs e)
        {
            if (ServiceOpenedEvent != null) ServiceOpenedEvent("Function Service", e);
        }
        #endregion
    }
}
